#include "MainGame.h"
#include "B2DebugDrawLayer.h"
#include "2d\CCSpriteBatchNode.h"
#include "2d\CCSpriteFrameCache.h"
#include "2d\CCSprite.h"
#include "base\CCVector.h"
#include "RotationGun.h"
#include "MoveGun.h"
#include "deprecated\CCDeprecated.h"
#include "base\CCValue.h"
#include "EnemyObject.h"
USING_NS_CC;

MainGame::MainGame()
{
}


MainGame::~MainGame()
{
}

Scene* MainGame::createScene()
{
	// 'scene' is an autorelease object
	auto scene = Scene::create();
	// 'layer' is an autorelease object
	auto layer = MainGame::create();
	// add layer as a child to scene
	scene->addChild(layer);
	// return the scene
	return scene;
}

// on "init" you need to initialize your instance
bool MainGame::init()
{
	//////////////////////////////
	// 1. super init first
	if (!Layer::init())
	{
		return false;
	}
	mCurrentGun = NULL;
	mGameSprite = Sprite::create();
	this->addChild(mGameSprite);
	scheduleUpdate();
	initWorld();
	mIsFight = true;
	spritebatch = SpriteBatchNode::create("content.png");
	cache = SpriteFrameCache::getInstance();
	cache->addSpriteFramesWithFile("content.plist");
	mGameSprite->addChild(spritebatch);
	// Create ball body 
	mBullet = new BulletObject(mWorld);
	mBullet->init(spritebatch,cache);
	mBullet->mBody->setPosition(b2Vec2(0, 600));
	mMap = CCTMXTiledMap::create("map/map_1.tmx");
	this->addChild(mMap);
	loadMap();

	pCloseItem = cocos2d::MenuItemImage::create(
		"CloseNormal.png",
		"CloseSelected.png",
		this,
		menu_selector(MainGame::menuCloseCallback));

	cocos2d::Menu* pMenu = cocos2d::Menu::create(pCloseItem, NULL);
	mGameSprite->setPosition(-mBullet->mBody->getPosition().x + Define::SCREEN_WIDTH / 2, 0);
	this->addChild(pMenu, 1);
	
	return true;
}

BaseObject* MainGame::makeObjectFromId(int id, b2World* world){
	switch (id)
	{
	case 0:
		return new GunObject(world);
	case 1:
		return new RotationGun(world);
	case 2:
		return new MoveGun(world);
	case 3:
		return new EnemyObject(mWorld);
	default:
		break;
	}
}
void MainGame::menuCloseCallback(cocos2d::Ref* pSender)
{
	if (mBullet->mCanFight == false)
		return;
	if (mCurrentGun!=NULL){
		mCurrentGun->setActive(false);
		mCurrentGun->mSprite->stopAllActions();
		mCurrentGun->mIsAction = false;
	}
	mCurrentGun = NULL;
	for (int i = 0; i < mBullet->mListJoint.size(); i++)
	{
		mWorld->DestroyJoint(mBullet->mListJoint[i]);
	}
	mBullet->mListJoint.clear();
		
	mBullet->mBody->mColBody->SetType(b2_dynamicBody);
	mBullet->mIsCollision = false;
	float g = mBullet->mBody->getAngle();
	float t = std::tan(g);
	float  y, alpha;
	alpha = mBullet->mBody->getAngle();
	mVector = std::sin(alpha) * 20;
	y = std::cos(alpha) * 20;
	mBullet->mBody->mColBody->SetLinearVelocity(b2Vec2(-mVector, y));
	mIsFight = true;
}
void MainGame::initWorld(){
	// Define the gravity vector.
	b2Vec2 gravity;
	gravity.Set(0.0f, Define::GRAVYTY);//No gravity

	// Do we want to let bodies sleep?
	bool doSleep = true;

	// create a world object, which will hold and simulate the rigid bodies.
	mWorld = new b2World(gravity);
	mWorld->SetAllowSleeping(false);

	B2DebugDrawLayer *debugdraw = B2DebugDrawLayer::create(mWorld, Define::PTM_RATIO);
	mGameSprite->addChild(debugdraw);

	mContactListener = new MyContactListener();
	mWorld->SetContactListener(mContactListener);
}

void MainGame:: update(float dt){
	mWorld->Step(dt, 10, 10);
	if (mIsFight == true && mIsOver == false){
		mGameSprite->setPosition(-mBullet->mBody->getPosition().x + Define::SCREEN_WIDTH / 2, 0);
	}
	mBullet->update(dt);
	for (int i = 0; i < mListGun.size(); i++)
	{
		mListGun.at(i)->update(dt);
	}


	std::vector<MyContact>::iterator pos;
	for (pos = mContactListener->_contacts.begin();
		pos != mContactListener->_contacts.end(); ++pos) {
		MyContact contact = *pos;

		BaseObject *objectA,*objectB;
		objectA = (BaseObject*)contact.fixtureA->GetBody()->GetUserData();
		objectB = (BaseObject*)contact.fixtureB->GetBody()->GetUserData();
		if (objectB != NULL && objectA != NULL){
			if (objectA->mId == OBJECT_BULLET ){
				if (objectB->mId == OBJECT_ENEMY)
				{
					mIsOver = true;
				}
				else
				{
					objectA->onCollisionWith(objectB);
					if (objectB->mId == OBJECT_GUN){
						mCurrentGun = (GunObject*)objectB;
						mIsFight = false;
					}
				}
				
			}
			if (objectB->mId == OBJECT_BULLET){
				if (objectA->mId == OBJECT_ENEMY)
				{
					mIsOver = true;
				}
				else
				{
					objectB->onCollisionWith(objectA);
					if (objectA->mId == OBJECT_GUN){
						mCurrentGun = (GunObject*)objectA;
						mIsFight = false;
					}
				}
				
			}
			if (mCurrentGun!=NULL && mCurrentGun->mAction != NULL)
				mCurrentGun->mSprite->stopAction(mCurrentGun->mAction);
		}

	}

}

void MainGame::loadMap()
{
	for (int i = 0; i < mMap->getObjectGroups().size(); i++){
		string gunName = "gun_" + std::to_string(i);
		CCTMXObjectGroup *objectGroup = mMap->objectGroupNamed(gunName);

		if (objectGroup == NULL){
			CCLog("tile map has no objects object layer");
			return ;
		}
		ValueVector groups = objectGroup->getObjects();
		for (int j = 0; j < groups.size(); j++){
			ValueMap spawnPoint = groups.at(j).asValueMap();
			int x = spawnPoint["x"].asInt();
			int y = spawnPoint["y"].asInt();
			GunObject* mGun = (GunObject*)makeObjectFromId(i, mWorld);
			mGun->init(spritebatch, cache, mGameSprite);
			mGun->setPosition(b2Vec2(x, y));
			mGun->initAction();
			mGun->mSprite->setScale(0);
			mListGun.push_back(mGun);
		}
	}
}

void MainGame::start()
{
	Scene *mainGame = MainGame::createScene();
	auto transition = TransitionFade::create(1.0f, mainGame);
	Director::getInstance()->replaceScene(transition);
}

void MainGame::stop()
{

}

